﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.DB;
using Autodesk.Revit.Exceptions;
using Autodesk.Revit.UI;
using YArchitech.Revit;
using HYView;
using ModelValidation.Analyser;
using ModelValidation.Utils;

namespace ModelValidation.Walls
{
	public class WallsValidationManager
	{
		public WallsValidationManager(ExternalCommandData cmdData)
		{
			this.m_UIApp = cmdData.Application;
			this.m_UIDoc = this.m_UIApp.ActiveUIDocument;
			this.m_App = this.m_UIApp.Application;
			this.m_Doc = this.m_UIDoc.Document;
		}

		public Result Validation(ref string message)
		{
			WallsValidationSettingForm wallsValidationSettingForm = new WallsValidationSettingForm();
			if (wallsValidationSettingForm.ShowDialog() != DialogResult.OK)
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			if (wallsValidationSettingForm.WallSelectType == WallsValidationSettingForm.SelectType.ST_ByBox)
			{
				return this.ValidationByBox(wallsValidationSettingForm);
			}
			if (wallsValidationSettingForm.WallSelectType == WallsValidationSettingForm.SelectType.ST_ByLayer)
			{
				return this.ValidationByLayer(wallsValidationSettingForm);
			}
			return this.ValidationByProject(wallsValidationSettingForm);
		}

		public Result WallClosedValidation(List<Wall> selWalls, double extendLength, ref List<ElementId> validationResult)
		{
			Result result;
			try
			{
				List<ElementId> list = new List<ElementId>();
				foreach (Wall wall in selWalls)
				{
					list.Add(wall.Id);
				}
				List<Level> list2 = new List<Level>();
				list2.Add(this.m_Doc.ActiveView.GenLevel);
				List<List<Pole2D>> list3 = new List<List<Pole2D>>();
				List<List<ElementId>> list4 = new List<List<ElementId>>();
				this.UpdateValidation(list, list2, true, extendLength, 1, false, ref list3, ref list4);
				foreach (Pole2D pole2D in list3[0])
				{
					if (!(pole2D.ComponentId == ElementId.InvalidElementId) && !(pole2D.ComponentId == null))
					{
						validationResult.Add(pole2D.ComponentId);
					}
				}
				foreach (ElementId elementId in list4[0])
				{
					if (!(elementId == ElementId.InvalidElementId) && !(elementId == null))
					{
						validationResult.Add(elementId);
					}
				}
				this.ChangeWallLoacation(list3[0], new List<ElementId>());
				result = Autodesk.Revit.UI.Result.Succeeded;
			}
			catch (Exception)
			{
				result = Autodesk.Revit.UI.Result.Failed;
			}
			return result;
		}

		private Result ValidationByBox(WallsValidationSettingForm dlg)
		{
			this.m_Settingdlg = dlg;
			IList<Wall> list = new List<Wall>();
			if (!this.SelectWalls(ref list))
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			List<ElementId> list2 = new List<ElementId>();
			foreach (Wall wall in list)
			{
				list2.Add(wall.Id);
			}
			this.m_lstWallIds.AddRange(list2);
			Result result;
			try
			{
				List<Level> list3 = new List<Level>();
				list3.Add(this.m_Doc.ActiveView.GenLevel);
				List<List<Pole2D>> list4 = new List<List<Pole2D>>();
				List<List<ElementId>> list5 = new List<List<ElementId>>();
				this.UpdateValidation(list2, list3, dlg.IsExtendLength, dlg.ExtendLength, dlg.WallWidthMultiple, true, ref list4, ref list5);
				this.UserSelect(list3, ref list4, ref list5);
				result = Autodesk.Revit.UI.Result.Succeeded;
			}
			catch (Exception)
			{
				result = Autodesk.Revit.UI.Result.Failed;
			}
			return result;
		}

		private Result ValidationByLayer(WallsValidationSettingForm dlg)
		{
			this.m_Settingdlg = dlg;
			Result result;
			try
			{
				List<Level> list = new List<Level>();
				list.Add(this.m_Doc.ActiveView.GenLevel);
				List<List<Pole2D>> list2 = new List<List<Pole2D>>();
				List<List<ElementId>> list3 = new List<List<ElementId>>();
				this.UpdateValidation(null, list, dlg.IsExtendLength, dlg.ExtendLength, dlg.WallWidthMultiple, true, ref list2, ref list3);
				this.UserSelect(list, ref list2, ref list3);
				result = Autodesk.Revit.UI.Result.Succeeded;
			}
			catch (Exception)
			{
				result = Autodesk.Revit.UI.Result.Failed;
			}
			return result;
		}

		private Result ValidationByProject(WallsValidationSettingForm dlg)
		{
			this.m_Settingdlg = dlg;
			List<Level> list = new List<Level>();
			if (!FloorSelectManager.SelectFloorLevels(this.m_Doc, ref list))
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			List<List<Pole2D>> list2 = new List<List<Pole2D>>();
			List<List<ElementId>> list3 = new List<List<ElementId>>();
			if (!this.UpdateValidation(null, list, dlg.IsExtendLength, dlg.ExtendLength, dlg.WallWidthMultiple, true, ref list2, ref list3))
			{
				return Autodesk.Revit.UI.Result.Failed;
			}
			if (this.UserSelect(list, ref list2, ref list3))
			{
				for (int i = 0; i < list.Count; i++)
				{
				}
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		public bool UpdateValidation(List<ElementId> selectWallIds, List<Level> floorPlanList, bool isExtendLength, double extendLength, int wallWidthMultiple, bool useMaximumLengthLimit, ref List<List<Pole2D>> analyzedPoleListOfProject, ref List<List<ElementId>> deleteWallIdsOfProject)
		{
			foreach (Level level in floorPlanList)
			{
				try
				{
					List<Pole2D> wallInfosByLevel = this.GetWallInfosByLevel(level);
					List<ElementId> list = new List<ElementId>();
					if (selectWallIds == null)
					{
						using (List<Pole2D>.Enumerator enumerator2 = wallInfosByLevel.GetEnumerator())
						{
							while (enumerator2.MoveNext())
							{
								Pole2D pole2D = enumerator2.Current;
								list.Add(pole2D.ComponentId);
							}
							goto IL_65;
						}
					}
					list.AddRange(selectWallIds);
					IL_65:
					wallInfosByLevel.AddRange(this.GetColumeInfosByLevel(level));
					List<Pole2D> analyzedPoleList = new List<Pole2D>();
					new PoleAnalyzer(isExtendLength, extendLength, wallWidthMultiple, useMaximumLengthLimit).Analyse(wallInfosByLevel, ref analyzedPoleList);
					List<Pole2D> item = new List<Pole2D>();
					new List<Curve>();
					List<ElementId> item2 = new List<ElementId>();
					this.FindChangeWall(analyzedPoleList, list, ref item, ref item2);
					analyzedPoleListOfProject.Add(item);
					deleteWallIdsOfProject.Add(item2);
				}
				catch (Exception)
				{
					return false;
				}
			}
			return true;
		}

		private bool SelectWalls(ref IList<Wall> selWalls)
		{
			bool result;
			try
			{
				foreach (Reference reference in this.m_UIDoc.Selection.PickObjects(Autodesk.Revit.UI.Selection.ObjectType.Element, new WallFilter(), "请选择参考线："))
				{
					selWalls.Add(this.m_Doc.GetElement(reference) as Wall);
				}
				result = true;
			}
			catch (Exception)
			{
				result = false;
			}
			return result;
		}

		private bool UserSelect(List<Level> floorPlanList, ref List<List<Pole2D>> analyzedPoleListOfProject, ref List<List<ElementId>> deleteWallIdListOfProject)
		{
			List<ViewPlan> floorInfo = new List<ViewPlan>();
			this.GetFloorListByLevels(floorPlanList, ref floorInfo);
			UserSelectForm userSelectForm = new UserSelectForm(floorInfo, this.m_UIDoc, analyzedPoleListOfProject, deleteWallIdListOfProject);
			userSelectForm.Show();
			List<List<KeyValuePair<Pole2D, int>>> list = new List<List<KeyValuePair<Pole2D, int>>>();
			for (;;)
			{
				userSelectForm.ResetContinueBreak();
				try
				{
					this.m_UIDoc.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element);
					continue;
				}
				catch (Exception ex)
				{
					if (!(ex is Autodesk.Revit.Exceptions.OperationCanceledException))
					{
						throw ex;
					}
					bool ifContinue = userSelectForm.IfContinue;
					bool ifBreak = userSelectForm.IfBreak;
					if (ifContinue)
					{
						list = userSelectForm.AnalyzedPoleListOfProject();
						deleteWallIdListOfProject = userSelectForm.DeleteWallIdListOfProject();
						for (int i = 0; i < list.Count; i++)
						{
							this.ChangeWallLoacation(analyzedPoleListOfProject[i], deleteWallIdListOfProject[i]);
						}
						if (this.m_lstWallIds == null)
						{
							list.Clear();
							analyzedPoleListOfProject.Clear();
							deleteWallIdListOfProject.Clear();
							this.UpdateValidation(null, floorPlanList, this.m_Settingdlg.IsExtendLength, this.m_Settingdlg.ExtendLength, this.m_Settingdlg.WallWidthMultiple, true, ref analyzedPoleListOfProject, ref deleteWallIdListOfProject);
							list = userSelectForm.GetAnalyzedPoleListOfProject(analyzedPoleListOfProject);
						}
						else
						{
							list.Clear();
							analyzedPoleListOfProject.Clear();
							deleteWallIdListOfProject.Clear();
							this.UpdateValidation(this.m_lstWallIds, floorPlanList, this.m_Settingdlg.IsExtendLength, this.m_Settingdlg.ExtendLength, this.m_Settingdlg.WallWidthMultiple, true, ref analyzedPoleListOfProject, ref deleteWallIdListOfProject);
							list = userSelectForm.GetAnalyzedPoleListOfProject(analyzedPoleListOfProject);
						}
						userSelectForm.RefreshTree(list, deleteWallIdListOfProject);
						continue;
					}
					if (!ifBreak)
					{
						continue;
					}
					if (userSelectForm.IfManualEsc)
					{
						userSelectForm.Close();
					}
				}
				break;
			}
			return false;
		}

		private void GetFloorListByLevels(List<Level> floorPlanList, ref List<ViewPlan> floorInfo)
		{
			List<ViewPlan> list = new List<ViewPlan>();
			foreach (Element element in new FilteredElementCollector(this.m_Doc).OfClass(typeof(ViewPlan)))
			{
				ViewPlan viewPlan = element as Autodesk.Revit.DB.ViewPlan;
				if (viewPlan != null && (int)viewPlan.ViewType == 1 && viewPlan.GenLevel != null)
				{
					list.Add(viewPlan);
				}
			}
			using (List<Level>.Enumerator enumerator2 = floorPlanList.GetEnumerator())
			{
				while (enumerator2.MoveNext())
				{
					Level level = enumerator2.Current;
					int num = list.FindIndex((ViewPlan item) => Geometry.IsEqual(item.GenLevel.Elevation, level.Elevation));
					if (num != -1)
					{
						floorInfo.Add(list[num]);
					}
				}
			}
		}

		private List<Pole2D> GetWallInfosByLevel(Level floorPlanLevel)
		{
			List<Wall> list = new List<Wall>();
			foreach (Element element in new FilteredElementCollector(this.m_Doc).OfClass(typeof(Wall)).ToElements())
			{
				Wall wall = element as Wall;
				ElementId elementId = wall.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT).AsElementId();
				try
				{
					if (!Geometry.IsEqual((this.m_Doc.GetElement(elementId) as Level).Elevation, floorPlanLevel.Elevation))
					{
						continue;
					}
				}
				catch (Exception)
				{
					continue;
				}
				list.Add(wall);
			}
			List<Pole2D> list2 = new List<Pole2D>();
			foreach (Wall wall2 in list)
			{
				double num = wall2.Width / 2.0;
				Pole2D item = null;
				Curve curve = (wall2.Location as LocationCurve).Curve;
				XYZ ptStart = Pole2D.To2D(curve.GetEndPoint(0));
				XYZ ptEnd = Pole2D.To2D(curve.GetEndPoint(1));
				Line line = curve as Line;
				if (null != line)
				{
					item = Pole2D.NewStructure2DPole(wall2.Id, ptStart, ptEnd, num, num);
				}
				Arc arc = curve as Arc;
				if (null != arc)
				{
					item = Pole2D.NewStructure2DPole(wall2.Id, ptStart, ptEnd, Pole2D.To2D(arc.Center), arc.Normal, num, num);
				}
				list2.Add(item);
			}
			return list2;
		}

		private List<Pole2D> GetColumeInfosByLevel(Level level)
		{
			List<Pole2D> list = new List<Pole2D>();
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(this.m_Doc, this.m_Doc.ActiveView.Id);
			foreach (Element element in filteredElementCollector.OfClass(typeof(FamilyInstance)).OfCategory(BuiltInCategory.OST_Columns).ToElements())
			{
				try
				{
					Parameter parameter = element.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_PARAM);
					if (parameter == null)
					{
						continue;
					}
					ElementId elementId = parameter.AsElementId();
					if (!Geometry.IsEqual((this.m_Doc.GetElement(elementId) as Level).Elevation, level.Elevation))
					{
						continue;
					}
				}
				catch (Exception)
				{
					continue;
				}
				foreach (Solid solid in this.GetElementSolids(element))
				{
					List<Pole2D> solidProfile = this.GetSolidProfile(solid);
					list.AddRange(solidProfile);
				}
			}
			new FilteredElementCollector(this.m_Doc, this.m_Doc.ActiveView.Id);
			foreach (Element element2 in filteredElementCollector.OfClass(typeof(FamilyInstance)).OfCategory(BuiltInCategory.OST_StructuralColumns).ToElements())
			{
				ElementId elementId2 = element2.get_Parameter(BuiltInParameter.SCHEDULE_BASE_LEVEL_PARAM).AsElementId();
				try
				{
					if (!Geometry.IsEqual((this.m_Doc.GetElement(elementId2) as Level).Elevation, level.Elevation))
					{
						continue;
					}
				}
				catch (Exception)
				{
					continue;
				}
				foreach (Solid solid2 in this.GetElementSolids(element2))
				{
					List<Pole2D> solidProfile2 = this.GetSolidProfile(solid2);
					list.AddRange(solidProfile2);
				}
			}
			return list;
		}

		private List<Solid> GetElementSolids(Element element)
		{
			Options options = this.m_UIApp.Application.Create.NewGeometryOptions();
			options.DetailLevel = (ViewDetailLevel)3;
			options.IncludeNonVisibleObjects = true;
			GeometryElement geometryElement;
			if (element.GetType() == typeof(FamilyInstance))
			{
				FamilyInstance familyInstance = element as FamilyInstance;
				geometryElement = familyInstance.GetOriginalGeometry(options);
				geometryElement = geometryElement.GetTransformed(familyInstance.GetTransform());
			}
			else
			{
				geometryElement = element.get_Geometry(options);
			}
			List<Solid> list = new List<Solid>();
			if (null == geometryElement)
			{
				return list;
			}
			foreach (GeometryObject geometryObject in geometryElement)
			{
				if (!(geometryObject.GetType() != typeof(Solid)))
				{
					Solid solid = geometryObject as Solid;
					if (solid != null && !Geometry.LessThan(solid.Volume, 0.001))
					{
						list.Add(solid);
					}
				}
			}
			return list;
		}

		private List<Pole2D> GetSolidProfile(Solid solid)
		{
			List<Pole2D> list = new List<Pole2D>();
			foreach (object obj in solid.Faces)
			{
				Face face = (Face)obj;
				if (!(face.GetType() != typeof(PlanarFace)))
				{
					PlanarFace face2 = face as PlanarFace;
					if (Geometry.IsEqual(face2.FaceNormal(), XYZ.BasisZ) || Geometry.IsEqual(face2.FaceNormal(), -XYZ.BasisZ))
					{
						foreach (object obj2 in face.EdgeLoops)
						{
							EdgeArray edgeArray = (EdgeArray)obj2;
							new List<EdgeInfo>();
							foreach (object obj3 in edgeArray)
							{
								Pole2D item = Pole2D.TransformWallToStructure2DPole(((Edge)obj3).AsCurve(), ElementId.InvalidElementId, 0.0, 0.0);
								list.Add(item);
							}
						}
					}
				}
			}
			return list;
		}

		private void FindChangeWall(List<Pole2D> analyzedPoleList, List<ElementId> wallIds, ref List<Pole2D> changedPoleList, ref List<ElementId> deleteWallIdList)
		{
			double eps = 0.001;
			using (List<Pole2D>.Enumerator enumerator = analyzedPoleList.GetEnumerator())
			{
				while (enumerator.MoveNext())
				{
					Pole2D pole = enumerator.Current;
					if (!(pole.ComponentId == ElementId.InvalidElementId))
					{
						int num = wallIds.FindIndex((ElementId item) => item.IntegerValue == pole.ComponentId.IntegerValue);
						if (num != -1)
						{
							Wall wall = this.m_Doc.GetElement(pole.ComponentId) as Wall;
							double length = (wall.Location as LocationCurve).Curve.Length;
							double val = pole.Length();
							if (!Geometry.IsEqual(length, val, eps))
							{
								Curve curve = (wall.Location as LocationCurve).Curve;
								Curve curve2 = pole.CenterCurve(curve.GetEndPoint(0).Z);
								if (pole.IsArcPole)
								{
									Arc arc = curve as Arc;
									Arc arc2 = curve2 as Arc;
									if (!Geometry.IsEqual(arc.Normal, arc2.Normal))
									{
										XYZ xyz = Geometry.CalculatMidPoint(arc2);
										curve2 = Arc.Create(curve2.GetEndPoint(1), curve2.GetEndPoint(0), xyz);
									}
								}
								else
								{
									Line line = curve as Line;
									Line line2 = curve2 as Line;
									if (!Geometry.IsEqual(line.Direction, line2.Direction))
									{
										curve2 = Line.CreateBound(curve2.GetEndPoint(1), curve2.GetEndPoint(0));
									}
								}
								Pole2D item2 = Pole2D.TransformWallToStructure2DPole(curve2, pole.ComponentId, 0.0, 0.0);
								changedPoleList.Add(item2);
							}
							wallIds.RemoveAt(num);
						}
					}
				}
			}
			deleteWallIdList.AddRange(wallIds);
		}

		private void ChangeWallLoacation(List<Pole2D> changedPoleList, List<ElementId> deleteWallIdList)
		{
			Transaction transaction = new Transaction(this.m_Doc);
			transaction.Start("change walls by checking result");
			for (int i = 0; i < changedPoleList.Count; i++)
			{
				Pole2D pole2D = changedPoleList[i];
				if (!(pole2D.ComponentId == ElementId.InvalidElementId))
				{
					Wall wall = this.m_Doc.GetElement(pole2D.ComponentId) as Wall;
					Curve curve = (wall.Location as LocationCurve).Curve;
					Curve curve2 = pole2D.CenterCurve(curve.GetEndPoint(0).Z);
					(wall.Location as LocationCurve).Curve = curve2;
				}
			}
			this.m_Doc.Delete(deleteWallIdList);
			transaction.Commit();
		}

		private ExternalCommandData m_CmdData;

		private UIApplication m_UIApp;

		private UIDocument m_UIDoc;

        private Autodesk.Revit.ApplicationServices.Application m_App;

		private Document m_Doc;

		private WallsValidationSettingForm m_Settingdlg;

		private List<ElementId> m_lstWallIds = new List<ElementId>();
	}
}
